package com.example.springbootlucenedemo.common.lucene.bean;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.springbootlucenedemo.bean.TbMission;
import com.example.springbootlucenedemo.common.lucene.annotation.*;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class EntityUtil {

    /**
     * doc所属的表或者对象
     */
    public static final String  table="table";
    /**
     * 获取路径
     * @param obj
     * @return
     */
    public static String getLuceneIndexPath(Object obj){
        Class<?> aClass = obj.getClass();
        boolean b = AnnotationUtil.hasAnnotation(aClass, LuceneIndexPath.class);
        if(b){
            Object luceneIndexPath = AnnotationUtil.getAnnotationValue(TbMission.class, LuceneIndexPath.class);
            return (String) luceneIndexPath;
        }
        return "";
    }

    /**
     * 获取主键
     * @param obj
     * @return
     */
    public static List<Query> getQueryByPrimarykey(Object obj){
        List<Query> queries = new ArrayList<>();
        Class<?> aClass = obj.getClass();
        java.lang.reflect.Field[] fields = ReflectUtil.getFields(aClass);
        for (java.lang.reflect.Field field:fields) {
            Object fidldVal = ReflectUtil.getFieldValue(obj, field);
            if(fidldVal == null){
                continue;
            }
            if(AnnotationUtil.hasAnnotation(field, Primarykey.class)){
                if(AnnotationUtil.hasAnnotation(field, LongPoint.class)){
                    queries.add( org.apache.lucene.document.LongPoint.newSetQuery(field.getName(),(Long)fidldVal));
                }
                if(AnnotationUtil.hasAnnotation(field, StringField.class)){
                    queries.add( new TermQuery(new Term(field.getName(),(String)fidldVal)));
                }
            }
        }
        return queries;
    }

    /**
     * 取得主键的 hashcode
     * @param obj
     * @return
     */
    public static long hashByPrimarykey(Object obj){
        Class<?> aClass = obj.getClass();
        java.lang.reflect.Field[] fields = ReflectUtil.getFields(aClass);
        List<String> keys = new ArrayList<>(fields.length);
        for (int i = 0; i < fields.length; i++) {
            Object fidldVal = ReflectUtil.getFieldValue(obj, fields[i]);
            if(fidldVal == null){
                continue;
            }
            if(AnnotationUtil.hasAnnotation(fields[i], Primarykey.class)){
                if(AnnotationUtil.hasAnnotation(fields[i], LongPoint.class)){
                    keys.add (String.valueOf(fidldVal));
                }
                if(AnnotationUtil.hasAnnotation(fields[i], StringField.class)){
                    keys.add (String.valueOf(fidldVal));
                }
            }
        }
        return hashByPrimarykeys(ArrayUtil.toArray(keys,String.class));
    }
    public static long hashByPrimarykeys(String... keys){
        StringBuffer keysb = new StringBuffer();
        for (Object key:keys) {
            if(null == key){
                continue;
            }
            keysb.append(key);
        }
        String join = StrUtil.join("", keysb);
        return HashUtil.fnvHash(join);
    }

    /**
     * 将定义的对象转换为 Document
     * @param obj
     * @return
     */
    public static Document parse(Object obj){
        Document document = new Document();
        Class aClass = obj.getClass();
        java.lang.reflect.Field[] fields = ReflectUtil.getFields(aClass);
        for (java.lang.reflect.Field field:fields) {
            Object fidldVal = ReflectUtil.getFieldValue(obj, field);
            if(fidldVal == null){
                continue;
            }
            boolean store = AnnotationUtil.hasAnnotation(field, StoredField.class);

            // TODO 待调整
            if (AnnotationUtil.hasAnnotation(field,StringField.class) ){
                String fieldName = AnnotationUtil.getAnnotationValue(field, StringField.class).equals("") ?field.getName():AnnotationUtil.getAnnotationValue(field, StringField.class);
                org.apache.lucene.document.Field.Store fieldStore = AnnotationUtil.getAnnotationValue(field, StringField.class, "fieldStore");
                document.add(new org.apache.lucene.document.StringField(fieldName,String.valueOf(fidldVal), Field.Store.NO));
                if(fieldStore.equals(Field.Store.YES)||store){
                    document.add(new org.apache.lucene.document.StoredField(fieldName,(String)fidldVal));
                }
            }else   if(AnnotationUtil.hasAnnotation(field,TextField.class)){
                String fieldName = AnnotationUtil.getAnnotationValue(field, TextField.class).equals("") ?field.getName():AnnotationUtil.getAnnotationValue(field, TextField.class);
                org.apache.lucene.document.Field.Store fieldStore = AnnotationUtil.getAnnotationValue(field, TextField.class, "fieldStore");
                document.add(new org.apache.lucene.document.TextField(fieldName,String.valueOf(fidldVal), Field.Store.NO));
                if(fieldStore.equals(Field.Store.YES)||store){
                    document.add(new org.apache.lucene.document.StoredField(fieldName,(String)fidldVal));
                }
            }else   if(AnnotationUtil.hasAnnotation(field, LongPoint.class)){
                String fieldName = AnnotationUtil.getAnnotationValue(field, LongPoint.class).equals("") ?field.getName():AnnotationUtil.getAnnotationValue(field, LongPoint.class);
                org.apache.lucene.document.Field.Store fieldStore = AnnotationUtil.getAnnotationValue(field, LongPoint.class, "fieldStore");
                document.add(new org.apache.lucene.document.LongPoint(fieldName, (long)fidldVal));
                document.add(new NumericDocValuesField(fieldName, (long)fidldVal ));
                if(fieldStore.equals(Field.Store.YES)||store){
                    document.add(new org.apache.lucene.document.StoredField(fieldName,(long)fidldVal));
                }
            }else   if(AnnotationUtil.hasAnnotation(field, FloatPoint.class)){
                String fieldName = AnnotationUtil.getAnnotationValue(field, FloatPoint.class).equals("") ?field.getName():AnnotationUtil.getAnnotationValue(field, FloatPoint.class);
                org.apache.lucene.document.Field.Store fieldStore = AnnotationUtil.getAnnotationValue(field, FloatPoint.class, "fieldStore");
                document.add(new org.apache.lucene.document.FloatPoint(fieldName, (float) fidldVal));
                if(fieldStore.equals(Field.Store.YES)||store){
                    document.add(new org.apache.lucene.document.StoredField(fieldName,(float)fidldVal));
                }
            }else   if(AnnotationUtil.hasAnnotation(field, DateField.class)){
                String fieldName = AnnotationUtil.getAnnotationValue(field, DateField.class).equals("") ?field.getName():AnnotationUtil.getAnnotationValue(field, DateField.class);
                org.apache.lucene.document.Field.Store fieldStore = AnnotationUtil.getAnnotationValue(field, DateField.class, "fieldStore");
                long date = ((Date) fidldVal).getTime() / 1000; //时间戳保留10位 与数据库unix_timestamp统一
                document.add(new org.apache.lucene.document.LongPoint(fieldName, date));
                document.add(new NumericDocValuesField(fieldName, date));
                if(fieldStore.equals(Field.Store.YES)||store){
                    document.add(new org.apache.lucene.document.StoredField(fieldName,date));
                }
            }
        }

        String name = AnnotationUtil.getAnnotationValue(aClass, LuceneIndexPath.class);
        document.add(new org.apache.lucene.document.StringField("table", name,  org.apache.lucene.document.Field.Store.YES));
        return document;
    }
}
